import newGameLib
from newGameLib import *
import Blender	

class PlanePart:
	def __init__(self):	
		self.name=None
		self.ID=None
		self.mountPoint=None
		self.stateList=[]
		self.vertices=None
		self.primitive=None
		self.node=None
		self.skeleton=None
		self.parentPart=None
		self.matList=[]
		self.bindBoneList=[]

	
intToBase64='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
	

class Item:
	def __init__(self):
		self.startOffset=None
		self.endOffset=None
		self.unk=None
		self.name=None
		self.data=None
		self.child=None
		self.nodeName=None
		
		
class Node:
	def __init__(self):
		self.name=None
		self.itemList=[]
		self.children=[]
		self.size=None
		self.headersize=None

def getNode(g):
	node=None
	node=Node() 
	node.itemCount=g.H(1)[0]
	node.offset=g.H(1)[0]
	node.unk=g.B(1)[0]
	node.type=g.B(1)[0]
	for m in range(node.itemCount):
		item=Item()
		item.name=stringList[g.H(1)[0]+1]
		item.endOffset=g.H(1)[0]
		item.unk=g.B(1)[0]
		item.type=g.B(1)[0]
		node.itemList.append(item)		
	return node 
	

def setNode(node,g,n):	
	n+=4
	start=g.tell()
	#print ' '*n,'start:',node.offset,node.unk,node.type
	txt.write(' '*n+'start:'+str(node.offset)+str(node.unk)+str(node.type)+'\n')
	if node.type==80:
		name=g.word(node.offset)
		string=decodeString(name)
		#print string
		node.name=string
		txt.write(' '*n+string+'\n')
	if node.type==16:
		string=g.word(node.offset)
		#print string
		node.name=string
		txt.write(' '*n+string+'\n')
	#print node.name	
		
	beginOffset=node.offset
	for i,item in enumerate(node.itemList):
		g.seek(start+beginOffset)
		#print ' '*n,item.endOffset,item.unk,item.type,item.name,g.tell()
		txt.write(' '*n+str(item.endOffset)+' '+str(item.unk)+' '+str(item.type)+' '+str(item.name)+' '+str(g.tell())+'\n')
		item.startOffset=g.tell()
		if item.type==0:
			item.nodeName=node.name	
			#print node.name
			child=getNode(g) 
			item.child=child
			setNode(child,g,n)
		if item.type==16:
			if i<node.itemCount:
				name=g.word(item.endOffset-beginOffset)
				#print name
				item.data=name
				txt.write(' '*n+name+'\n')
		if item.type==80:
			if i<node.itemCount:
				name=g.word(item.endOffset-beginOffset)
				string=decodeString(name)
				#print string
				item.data=string
				txt.write(' '*n+string+'\n')
			
			
		beginOffset=item.endOffset		

		
		
	
def decodeString(a): 
	aLen = len(a)
	numFullGroups = aLen / 3
	numBytesInPartialGroup = aLen - 3 * numFullGroups
	resultLen = 4 * ((aLen + 2) / 3)
	result = ''
	inCursor = 0
	for i in range(numFullGroups):
		byte0 = ord(a[inCursor]) & 0xff
		inCursor+=1
		byte1 = ord(a[inCursor]) & 0xff
		inCursor+=1
		byte2 = ord(a[inCursor]) & 0xff
		inCursor+=1
		result+=intToBase64[byte0 >> 2]
		result+=intToBase64[(byte0 << 4) & 0x3f | (byte1 >> 4)]
		result+=intToBase64[(byte1 << 2) & 0x3f | (byte2 >> 6)]
		result+=intToBase64[byte2 & 0x3f]
	return result
	
		
def xmlParser(filename,g):
	global stringList,txt
	txt=open(filename+'.txt','w')
	stringList=[]
	while(True):
		string=g.find('\x00')
		if len(string)>0:stringList.append(string)
		else:break					
	n=0
	root=getNode(g) 
	setNode(root,g,n)
	txt.close()
	return root
	
	
def visualParser(filename,g,root):	
	skeleton=Skeleton()
	skeleton.extraBoneNameList=[]
	skeleton.name=os.path.basename(filename).split('.')[0]
	print skeleton.name
	skeleton.NICE=True
	skeleton.BONESPACE=True	
	partList=[]
	def getBone(parentBone,parentItem,n,g):
		n+=4
		bone=Bone()
		bone.parentName=parentBone.name
		skeleton.boneList.append(bone)
		for item in parentItem.child.itemList:
			if item.name=='node':getBone(bone,item,n,g)
			if item.name=='identifier':
				if item.data is not None:
					bone.name=item.data[-25:]
					skeleton.extraBoneNameList.append(item.data[-25:])
			if item.name=='transform':
				g.seek(item.startOffset)
				rot=Matrix3x3(g.f(9)).resize4x4()
				pos=VectorMatrix(g.f(3))
				matrix=rot*pos
				bone.matrix=matrix	
	n=0	
	for item in root.itemList:
		if item.name=='node':
			bone=Bone()
			skeleton.boneList.append(bone)
			getBone(bone,item,n,g)
		if item.name=='renderSet':
			part=PlanePart()
			part.skeleton=skeleton.name
			partList.append(part)	
			for item1 in item.child.itemList:
				if item1.name=='geometry':
					for item2 in item1.child.itemList:
						if item2.name=='vertices':part.vertices=item2.data
						if item2.name=='primitive':part.primitive=item2.data
						if item2.name=='primitiveGroup':
							for item3 in item2.child.itemList:							
								if item3.name=='material':
									mat=Mat()
									part.matList.append(mat)
									for item4 in item3.child.itemList:
										if item4.name=='property':
											matType=item4.child.name
											for item5 in item4.child.itemList:
												if item5.name=='Texture':
													if matType=='diffuseTexMap':
														mat.diffuse=item5.data
													if matType=='normalTexMap':
														mat.normal=item5.data
													if matType=='specularTexMap':
														mat.specular=item5.data
									
							
				if item1.name=='node':
					bindBone=item1.data
					part.bindBoneList.append(bindBone[-25:])
		#if item.name=='boundingBox':
		#	for item1 in item.child.itemList:
		#		if item1.name=='min':g.seek(item1.startOffset)
		#		if item1.name=='max':g.seek(item1.startOffset)
	skeleton.draw()		
	return partList	
															
	
def partDraw(filename,g,part):
		print '-'*70
		print filename
		print	

		#if part.skeleton is not None:
		#	part.skeleton.draw()

		modelName=part.name		
		streamList={}
		primitivesPath=filename.lower().replace('.visual','.primitives')
		if os.path.exists(primitivesPath)==True:
			file=open(primitivesPath,'rb')
			g=BinaryReader(file)
			streamList=primitivesParser(primitivesPath,g)
			file.close()	
	
	
		
		mesh=Mesh()
		mesh.TRIANGLE=True
		skin=Skin()
		mesh.skinList.append(skin)
		streamName=part.vertices
		if streamName in streamList.keys():			
			primitivesPath=filename.lower().replace('.visual','.primitives')
			if os.path.exists(primitivesPath)==True:
				file=open(primitivesPath,'rb')
				g=BinaryReader(file)
				g.seek(streamList[streamName][0])
				getStream(mesh,g)
				file.close()
				
				
		streamName=part.primitive
		if streamName in streamList.keys():			
			primitivesPath=filename.lower().replace('.visual','.primitives')
			if os.path.exists(primitivesPath)==True:
				file=open(primitivesPath,'rb')
				g=BinaryReader(file)
				g.seek(streamList[streamName][0])
				getStream(mesh,g)
				file.close()
				


				
		mesh.name=part.name
		if part.skeleton is not None:	
			mesh.BINDSKELETON=part.skeleton
			mesh.boneNameList=part.bindBoneList
		for i,mat in enumerate(mesh.matList):
			if len(part.matList)-1>=i:
				if part.matList[i].diffuse is not None:
					mat.diffuse=g.dirname+os.sep+'texture'+os.sep+os.path.basename(part.matList[i].diffuse).split('.')[0]+'.dds'
		mesh.draw()		
	
	
	
def getStream(mesh,g):	
	t=g.tell()
	chunk=g.find('\x00')
	if chunk =='xyznuviiiww':
		g.seek(t+64)
		count=g.i(1)[0]					
		for m in range(count):
			t=g.tell()
			mesh.vertPosList.append(g.f(3))
			g.seek(t+16)
			mesh.vertUVList.append(g.f(2))
			i1=g.B(1)[0]/3
			i2=g.B(1)[0]/3
			i3=g.B(1)[0]/3
			mesh.skinIndiceList.append([i1,i2])
			w1,w2=g.B(2)
			w3=255-(w1+w2)
			mesh.skinWeightList.append([w1,w2])
			g.seek(t+29)
		g.seekpad(4)	
		
		
	elif chunk =='xyznuvtb':
		g.seek(t+64)
		count=g.i(1)[0]					
		for m in range(count):
			t=g.tell()
			mesh.vertPosList.append(g.f(3))
			g.seek(t+16)
			mesh.vertUVList.append(g.f(2))
			g.seek(t+32)
		g.seekpad(4)	
		
	elif chunk =='xyznuv':
		g.seek(t+64)
		count=g.i(1)[0]					
		for m in range(count):
			t=g.tell()
			mesh.vertPosList.append(g.f(3))
			g.seek(t+16)
			mesh.vertUVList.append(g.f(2))
			g.seek(t+32)
		g.seekpad(4)	
		
		
	elif chunk =='xyznuviiiwwtb':
		g.seek(t+64)
		count=g.i(1)[0]					
		for m in range(count):
			t=g.tell()
			mesh.vertPosList.append(g.f(3))
			g.seek(t+16)
			mesh.vertUVList.append(g.f(2))
			i1=g.B(1)[0]/3
			i2=g.B(1)[0]/3
			i3=g.B(1)[0]/3
			mesh.skinIndiceList.append([i1,i2])
			w1,w2=g.B(2)
			w3=255-(w1+w2)
			mesh.skinWeightList.append([w1,w2])
			g.seek(t+37)
		g.seekpad(4)	
		
	elif chunk=='list':
		g.seek(t+64)
		a,b=g.i(2)
		mesh.indiceList=g.H(a)	
		for m in range(b):
			mat=Mat()
			mat.TRIANGLE=True
			B=g.i(4)
			mat.IDStart=B[0]
			mat.IDCount=B[1]*3
			mesh.matList.append(mat)
		g.seekpad(4)
	else:
		print 'WARNING:unknow chunk:',chunk

		
	
def primitivesParser(filename,g):
		
	streamList={}
	g.seek(-4,2)
	pos=g.tell()
	offset=g.i(1)[0]+4
	g.seek(-offset,2)
	offset=4
	while(True):
		a,b,c,d,e=g.i(5)
		streamName=g.word(g.i(1)[0]).strip()
		streamList[streamName]=[offset,a]
		g.seekpad(4)
		t=g.tell()
		g.seek(offset+a)
		g.seekpad(4)
		offset=g.tell()
		g.seek(t)
		if g.tell()==pos:break
	g.tell()
	return  streamList
							
	
def Parser(filename):
	ext=filename.split('.')[-1].lower()	
	
	
	if ext=='visual':
		file=open(filename,'rb')
		g=BinaryReader(file)
		root=xmlParser(filename,g)
		partList=visualParser(filename,g,root)
		for part in partList:partDraw(filename,g,part)		
		file.close()
 
 
	
Blender.Window.FileSelector(Parser,'import','select: *.visual') 
	